/****************************************************************************/ 
/** The contents of this file are released under the MIT License, a copy of */
/** which is included in the LICENSE file that should have been distributed */
/** with the source code.                                                   */
/****************************************************************************/

var myWamiApp; // an instance of the remote WAMI application

var jsgf = "#JSGF V1.0;\n" +
      "grammar chrovox;\n" +
      "public <top> = <command>+;\n" +
      "<command> = go back {[command=back]}\n" +
      "          | go forward {[command=forward]}\n" +
      "          | reload {[command=reload]} | refresh {[command=reload]}\n" + 
      "          | new tab {[command=newtab]} | close tab {[command=closetab]}\n" +
      "          | yes {[command=okay]} | cancel {[command=wrong]};";

var com = {

  execute: function(command) {
    commands[command]();
  },
  
  back: function() {
    LOG("back");
    util.gBrowser().goBack();
  },
  
  forward: function() {
    LOG("forward");
    util.gBrowser().goForward();
  },
  
  reload: function() {
    LOG("reload");
    util.gBrowser().reload();        
  },

  newtab: function() {
    LOG("newtab");
    util.gBrowser().selectedTab = util.gBrowser().addTab();
    util.gBrowser().goHome();    
  },
  
  closetab: function() {
    LOG("closetab");
    if (util.gBrowser().tabContainer.itemCount > 1) {
      util.gBrowser().removeTab(util.gBrowser().selectedTab);
    }
  },
  
  okay: function() {
    LOG("okay");
  },

  wrong: function() {
    LOG("wrong");
  }  
};


/**
 * The commands, as listed in the jsgf grammar above, and their corresponding
 * methods. These will be called when a command is recognized by WAMI
 */
var commands = {
  "back"    : com.back,
  "forward" : com.forward,
  "reload"  : com.reload,
  "newtab"  : com.newtab,
  "closetab": com.closetab,
  "okay"    : com.okay,
  "wrong"   : com.wrong
};


/**
 * Utility methods
 */
var util = {
  gBrowser: function() {
    var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(Components.interfaces.nsIWindowMediator);
    var mainWindow = wm.getMostRecentWindow("navigator:browser");
    return mainWindow.gBrowser;    
  }

}

/**
 * Wraps configuration and initialization code for the WAMI application. Call
 * methods in this wrapper only after the remote WAMI script is loaded in the
 * remote iframe.
 */
var wamiWrapper = {

  /**
   * Called when the WAMI framework is ready
   */
  onWamiReady: function() {
    myWamiApp.speak("fire vox ready");
    var button = window.document.getElementById('toggle-recording-command');
    button.label="Start Recording";
  },

  /**
   * Called when a voice recognition result is available
   */
  onWamiRecognitionResult: function(result) {
    
    // only process valid, final recognition results
    if(!result.hyps || result.hyps.length == 0 || 
      !result.hyps[0].aggregate || 
      result.hyps[0].aggregate.partial ) {
      return;
    }

    //key value pairs
    var aggregate = result.hyps[0].aggregate;

    var kvs = aggregate.kvs;      
    // process command
    if (kvs.command != null) {
      com.execute(kvs.command);
    }
  },

  /**
   * Called on WAMI error
   */
  onWamiError: function(type, msg) {
    alert("WAMI error: type  = " + type + ", message = " + msg);
  },

  /**
   * Called when WAMI times out, possibly due to no user input
   */
  onWamiTimeout: function() {
    alert("WAMI timed out.");
  },

  init: function() {
    
    //div in which to put the audio button, see below
    var audioDiv = window.frames[0].document.getElementById('wami-audio-container');

    var grammar = {
      "language" : "en-us", 
      "grammar"  : jsgf 
    };

    
    var audioOptions = {
      "width"        : "300",
      "height"       : "100",
      "hideButton"   : true, 
      "pollForAudio" : true
    };


    var configOptions = {
      "sendIncrementalResults" : true,    // receive "incremental" recognition results as the user speaks
      "sendAggregates"         : true     // receive a "semantic" interpretation
    };

    // handlers are all qualified with parent; remember, the WAMI script lives in an iframe
    var handlers = {
      "onReady"             : parent.wamiWrapper.onWamiReady,                // WAMI is loaded and ready
      "onRecognitionResult" : parent.wamiWrapper.onWamiRecognitionResult,    // Speech recognition result available
      "onError"             : parent.wamiWrapper.onWamiError,                // An error occurred
      "onTimeout"           : parent.wamiWrapper.onWamiTimeout               // WAMI timed out due to inactivity
    }; 
               
    // WAMI script is in a frame, obtain a reference to WamiApp
    var WamiApp = window.frames[0].WamiApp;
    // Create WAMI application
    myWamiApp = new WamiApp(audioDiv, handlers, "json", audioOptions, configOptions, grammar);  
  }

};


/**
 * Injects the WAMI script in the remote frame; when script finishes loading,
 * calls wamiWrapper.init
 */
var wamiInjector = {
  inject: function() {
    var headID = window.frames[0].document.getElementsByTagName("head")[0];         
    var newScript = window.frames[0].document.createElement('script');
    newScript.type   = 'text/javascript';
    newScript.onload = wamiWrapper.init;
    newScript.src    = 'http://wami.csail.mit.edu/portal/wami.js?devKey=8785f1fd0296287a54c66f8aadca179b';
    headID.appendChild(newScript);
  }
};


var ui = {
  onToggleRecordingCommand: function(e) {
    var button = window.document.getElementById('toggle-recording-command');
    if ("Start Recording"==button.label) {
      myWamiApp.startRecording();
      button.label="Stop Recording";
    } else {
      myWamiApp.stopRecording();
      button.label="Start Recording";
    }
  }
  
};


function LOG(msg) {
  var consoleService = Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
  consoleService.logStringMessage(msg);
}


window.addEventListener("load", wamiInjector.inject, false);